﻿using System;
using UnityEngine;

namespace Core
{
    public class DataView<T>
    {
        protected T[,] Data;

        public int W { get; private set; }
        public int H { get; private set; }

        private int offsetX, offsetY;

        public DataView(int w, int h)
        {
            Data = new T[w, h];
            Awake(Data, 0, 0, w, h);
        }

        public DataView(T[,] data, int x, int y, int width, int height)
        {
            Awake(data, x, y, width, height);
        }

        private void Awake(T[,] data, int x, int y, int width, int height)
        {
            this.Data = data;
            offsetX = x; offsetY = y;
            W = width; H = height;
        }

        public DataView<T> CreateView(int x, int y, int w, int h)
        {
            return new DataView<T>(Data, x, y, w, h);
        }

        public T GetElement(int x, int y)
        {
            return Data[x + offsetX, y + offsetY];
        }

        public void SetElement(int x, int y, T t)
        {
            Data[x + offsetX, y + offsetY] = t;
        }

        public T this[int x, int y]
        {
            get
            {
                if (x < 0 || x >= W || y < 0 || y >= H)
                {
                    return default;
                }

                return GetElement(x, y);
            }
            set
            {
                if (x < 0 || x >= W || y < 0 || y >= H)
                {
                    return;
                }

                SetElement(x, y, value);
            }
        }

        public T this[Vector2Int point]
        {
            get => this[point.x, point.y];
            set => this[point.x, point.y] = value;
        }

        public T this[int index]
        {
            get
            {
                //return dataArr[index];
                int x = index / W;
                int y = index % W;
                return this[x, y];
            }
            set
            {
                int x = index / W;
                int y = index % W;
                this[x, y] = value;
            }
        }

        public bool Contains(Vector2Int point)
        {
            return this[point] != null;
        }

        public virtual void Clear()
        {
            Data = null;
            //dataArr = null;
        }

        protected void Do(int x, int y, Action<T> func)
        {
            if (func == null) return;

            var n = this[x, y];
            if (n != null)
            {
                func(n);
            }
        }

        protected bool Do(int x, int y, Func<T, bool> func)
        {
            if (func == null) return false;

            var n = this[x, y];
            if (n == null)
            {
                return false;
            }

            return func(n);
        }

        /// <summary>
        /// 全遍历
        /// </summary>
        /// <param name="func"></param>
        public void Foreach(Action<T> func)
        {
            if (func == null) return;

            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    var n = this[i, j];
                    if (n != null)
                    {
                        func(n);
                    }
                }
            }
        }

        /// <summary>
        /// 全遍历
        /// </summary>
        /// <param name="func"></param>
        public void Foreach(Action<int, int, T> func)
        {
            if (func == null) return;

            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    var n = this[i, j];
                    if (n != null)
                    {
                        func(i, j, n);
                    }
                }
            }
        }

        /// <summary>
        /// 全遍历
        /// 满足condition_func的节点会执行action_func
        /// </summary>
        /// <param name="conditionFunc">条件回调</param>
        /// <param name="actionFunc">行为回调</param>
        public void Foreach(Func<T, bool> conditionFunc, Action<T> actionFunc)
        {
            if (actionFunc == null) return;

            for (var j = 0; j < H; j++)
            {
                for (var i = 0; i < W; i++)
                {
                    var n = this[i, j];
                    if (n == null)
                    {
                        continue;
                    }
                    if (conditionFunc == null || conditionFunc(n))
                    {
                        actionFunc(n);
                    }
                }
            }
        }
        /// <summary>
        /// 根据传递的索引数组进行遍历
        /// </summary>
        /// <param name="arr">索引数组</param>
        /// <param name="func"></param>
        public void Foreach(int[] arr, Action<T> func)
        {
            if (func == null) return;

            for (int i = 0; i < arr.Length; i++)
            {
                var n = this[arr[i]];
                if (n != null)
                {
                    func(n);
                }
            }
        }

        /// <summary>
        /// 特殊遍历1 -> 左右分离
        /// </summary>
        /// <param name="cnt">遍历的个数</param>
        /// <param name="func"></param>
        public void Foreach0(int cnt, Action<T> func)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, W * H);

            int len = 0;
            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    if (len >= cnt)
                    {
                        return;
                    }
                    var n = this[i, j];
                    if (n == null)
                    {
                        continue;
                    }
                    func(this[i, j]);
                    len++;
                }
            }
        }

        /// <summary>
        /// 特殊遍历1 -> 左右分离
        /// </summary>
        /// <param name="cnt">遍历的个数</param>
        /// <param name="func"></param>
        public void Foreach1(int cnt, Action<T> func)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, W * H);

            int len = cnt / 2;
            T n;
            for (int k = 0; k < len; k++)
            {
                int i = k / H;
                int j = k % H;

                n = this[i, j];
                if (n != null)
                {
                    func(n);
                }

                n = this[W - i - 1, H - j - 1];
                if (n != null)
                {
                    func(n);
                }
            }

            if (len * 2 == cnt - 1)
            {
                int i = len / H;
                int j = len % H;
                n = this[i, j];
                if (n != null)
                {
                    func(n);
                }
            }
        }

        /// <summary>
        /// 特殊遍历2 -> 对角分离 左上，右下
        /// </summary>
        /// <param name="cnt"></param>
        /// <param name="func"></param>
        public void Foreach2(int cnt, Action<T> func)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, W * H);

            int len = Mathf.Max(W, H);
            int cc = 0;
            for (int k = 0; k <= len; k++)
            {
                for (int m = 0; m <= k; m++)
                {
                    int i = m;
                    int j = k - m;

                    if (i < 0 || i >= W || j < 0 || j >= H)
                    {
                        continue;
                    }

                    if (cc++ >= cnt) { return; }

                    var n = this[i, j];
                    if (n != null)
                    {
                        func(n);
                    }

                    if (cc++ >= cnt) { return; }

                    n = this[W - i - 1, H - j - 1];
                    if (n != null)
                    {
                        func(n);
                    }
                }
            }
        }

        /// <summary>
        /// 特殊遍历3 -> 上下分离
        /// </summary>
        /// <param name="cnt">遍历的个数</param>
        /// <param name="func"></param>
        public void Foreach3(int cnt, Action<T> func)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, W * H);

            T n;
            int len = cnt / 2;
            for (int k = 0; k < len; k++)
            {
                int i = k % W;
                int j = k / W;

                n = this[i, j];
                if (n != null)
                {
                    func(n);
                }

                n = this[W - i - 1, H - j - 1];
                if (n != null)
                {
                    func(n);
                }
            }
            if (len * 2 == cnt - 1)
            {
                int i = len % W;
                int j = len / W;

                n = this[i, j];
                if (n != null)
                {
                    func(n);
                }
            }
        }

        /// <summary>
        /// 特殊遍历4 -> 对角分离 左下，右上
        /// </summary>
        /// <param name="cnt"></param>
        /// <param name="func"></param>
        public void Foreach4(int cnt, Action<T> func)
        {
            if (cnt <= 0 || func == null) return;
            cnt = Mathf.Min(cnt, W * H);

            int len = Mathf.Max(W, H);
            int cc = 0;
            for (int k = 0; k <= len; k++)
            {
                for (int m = 0; m <= k; m++)
                {
                    int i = m;
                    int j = H - (k - m) - 1;

                    if (i < 0 || i >= W || j < 0 || j >= H)
                    {
                        continue;
                    }

                    if (cc++ >= cnt) { return; }

                    var n = this[i, j];
                    if (n != null)
                    {
                        func(n);
                    }

                    if (cc++ >= cnt) { return; }

                    n = this[W - i - 1, H - j - 1];
                    if (n != null)
                    {
                        func(n);
                    }
                }
            }
        }

        /// <summary>
        /// 统计满足条件的节点个数，
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        public int Count(Func<T, bool> func)
        {
            int cnt = 0;

            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    var n = this[i, j];

                    if (n != null)
                    {
                        if (func != null)
                        {
                            cnt += func(n) ? 1 : 0;
                        }
                        else
                        {
                            cnt++;
                        }
                    }
                }
            }

            return cnt;
        }
        /// <summary>
        /// 遍历(x,y)节点的周围第num圈节点
        /// 不包括圈内节点
        /// 不返回自身节点
        /// 不返回无效节点
        ///
        /// 若需要包括圈内节点的方法，请调用ForRoundIn方法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="func"></param>
        /// <param name="num">以(x,y)为中心向外第num圈</param>
        public void ForRoundOn(int x, int y, Action<T> func, int num = 1)
        {
            if (func == null || num <= 0) return;

            for (var j = -num; j < num; j++)
            {
                Do(x - num, y + j, func);
            }
            for (var i = -num; i < num; i++)
            {
                Do(x + i, y + num, func);
            }
            for (var j = num; j > -num; j--)
            {
                Do(x + num, y + j, func);
            }
            for (var i = num; i > -num; i--)
            {
                Do(x + i, y - num, func);
            }
        }

        public bool FindRoundOn(int x, int y, Func<T, bool> func, int num = 1)
        {
            if (func == null || num <= 0) return false;

            bool result = false;

            for (var j = -num; j < num; j++)
            {
                result = Do(x - num, y + j, func);
                if (result) break;
            }

            if (result) return true;

            for (var i = -num; i < num; i++)
            {
                result = Do(x + i, y + num, func);
                if (result) break;
            }

            if (result) return true;

            for (var j = num; j > -num; j--)
            {
                result = Do(x + num, y + j, func);
                if (result) break;
            }

            if (result) return true;

            for (var i = num; i > -num; i--)
            {
                result = Do(x + i, y - num, func);
                if (result) break;
            }

            return result;
        }

        /// <summary>
        /// 遍历(x,y)节点的周围num圈节点
        /// 包括圈内节点
        /// 不返回自身节点
        /// 不返回无效节点
        ///
        /// 若需要不包括圈内节点的方法，请调用ForRoundOn方法
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="func"></param>
        /// <param name="num">圈数，默认为1</param>
        public void ForRoundIn(int x, int y, Action<T> func, int num = 1)
        {
            if (func == null) return;

            for (int i = -num; i <= num; i++)
            {
                for (int j = -num; j <= num; j++)
                {
                    if (i == 0 && j == 0)
                    {
                        continue;
                    }
                    Do(x + i, y + j, func);
                }
            }
        }

        /// <summary>
        /// 整个DataView有外圈向内圈遍历
        /// </summary>
        /// <param name="func"></param>
        public void ForRoundO2I(Action<T> func)
        {
            if (func == null) return;
            var size = Mathf.Max(W, H);
            var centerX = W / 2;
            var centerY = H / 2;
            var radius = size / 2;
            for (var i = radius; i >= 0; i--)
            {
                ForRoundOn(centerX, centerY, func, i);
            }
        }

        /// <summary>
        /// 整个DataView有内圈向外圈遍历
        /// </summary>
        /// <param name="func"></param>
        public void ForRoundI2O(Action<T> func)
        {
            if (func == null) return;
            var size = Mathf.Max(W, H);
            var centerX = W / 2;
            var centerY = H / 2;
            var radius = size / 2;
            for (var i = 0; i <= radius; i++)
            {
                ForRoundOn(centerX, centerY, func, i);
            }
        }

        public void ForRound(Action<int, int, T> func)
        {
            if (func == null) return;

            for (var i = 0; i < W; i++)
            {
                func(i, 0, this[i, 0]);
            }
            for (var j = 1; j < H; j++)
            {
                func(W - 1, j, this[W - 1, j]);
            }
            for (var i = W - 2; i >= 0; i--)
            {
                func(i, H - 1, this[i, H - 1]);
            }
            for (var j = H - 2; j >= 1; j--)
            {
                func(0, j, this[0, j]);
            }
        }

        /// <summary>
        /// 统计(x,y)节点周围满足条件的节点个数，
        /// 默认返回周围有效的节点数，
        /// 不包含自身(x,y)节点
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public int CountRound(int x, int y, Func<T, bool> func)
        {
            int cnt = 0;

            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    if (i == 0 && j == 0)
                    {
                        continue;
                    }

                    var n = this[x + i, y + j];
                    if (n != null)
                    {
                        if (func != null)
                        {
                            cnt += func(n) ? 1 : 0;
                        }
                        else
                        {
                            cnt++;
                        }
                    }
                }
            }

            return cnt;
        }

        //public void ForEdge(Action<T> func)
        //{

        //}


        public void Do(Func<T, bool> filter, Func<T, T, bool> compare, Func<T, T, bool> func)
        {
            if (func == null || filter == null || compare == null) return;

            for (int j1 = 0; j1 < H; j1++)
            {
                for (int i1 = 0; i1 < W; i1++)
                {
                    var n1 = this[i1, j1];
                    if (filter(n1))
                    {
                        continue;
                    }

                    for (int j2 = j1; j2 < H; j2++)
                    {
                        for (int i2 = i1 + 1; i2 < W; i2++)
                        {
                            var n2 = this[i2, j2];
                            if (filter(n1))
                            {
                                continue;
                            }

                            if (compare(n1, n2))
                            {
                                var result = func(n1, n2);
                                if (result)
                                {
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }

        public void Do(Func<T, bool> filter, Func<T, T, bool> compare, Action<T, T> func)
        {
            if (func == null || filter == null || compare == null) return;

            for (int j1 = 0; j1 < H; j1++)
            {
                for (int i1 = 0; i1 < W; i1++)
                {
                    var n1 = this[i1, j1];
                    if (filter(n1))
                    {
                        continue;
                    }

                    for (int j2 = j1; j2 < H; j2++)
                    {
                        for (int i2 = i1 + 1; i2 < W; i2++)
                        {
                            var n2 = this[i2, j2];
                            if (filter(n1))
                            {
                                continue;
                            }

                            if (compare(n1, n2))
                            {
                                func(n1, n2);
                            }
                        }
                    }
                }
            }
        }

        public bool Any(Func<T, bool> func)
        {
            if (func == null) return false;

            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    if (func(this[i, j]))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public bool All(Func<T, bool> func)
        {
            if (func == null) return false;

            for (int j = 0; j < H; j++)
            {
                for (int i = 0; i < W; i++)
                {
                    if (!func(this[i, j]))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// 检测，任意一对元素符合条件即可
        /// </summary>
        /// <param name="func">检测条件</param>
        /// <param name="type">0：所有元素；1：逐行；2：逐列</param>
        /// <returns></returns>
        public bool Any(Func<T, T, bool> func, int type = 0)
        {
            if (func == null || type < 0 || type > 2) return false;

            switch (type)
            {
                case 0:
                    {
                        int cnt = H * W;
                        for (int i = 0; i < cnt - 1; i++)
                        {
                            for (int j = i + 1; j < cnt; j++)
                            {
                                if (func(this[i], this[j]))
                                {
                                    return true;
                                }
                            }
                        }
                    }
                    break;
                case 1:
                    {
                        for (int j = 0; j < H; j++)
                        {
                            for (int k1 = 0; k1 < W - 1; k1++)
                            {
                                if (func(this[k1, j], this[k1 + 1, j]))
                                {
                                    return true;
                                }
                            }
                        }
                    }
                    break;
                case 2:
                    {
                        for (int i = 0; i < W; i++)
                        {
                            for (int k1 = 0; k1 < H - 1; k1++)
                            {
                                if (func(this[i, k1], this[i, k1 + 1]))
                                {
                                    return true;
                                }
                            }
                        }
                    }
                    break;
            }
            return false;
        }

        /// <summary>
        /// 检测，每一个元素都需要符合条件
        /// </summary>
        /// <param name="func">检测条件</param>
        /// <param name="type">0：所有元素；1：逐行；2：逐列</param>
        /// <returns></returns>
        public bool All(Func<T, T, bool> func, int type = 0)
        {
            if (func == null || type < 0 || type > 2) return false;

            switch (type)
            {
                case 0:
                    {
                        int cnt = H * W;
                        for (int i = 0; i < cnt - 1; i++)
                        {
                            for (int j = i + 1; j < cnt; j++)
                            {
                                if (!func(this[i], this[j]))
                                {
                                    return false;
                                }
                            }
                        }
                    }
                    break;
                case 1:
                    {
                        for (int j = 0; j < H; j++)
                        {
                            for (int k1 = 0; k1 < W - 1; k1++)
                            {
                                for (int k2 = k1 + 1; k2 < W; k2++)
                                {
                                    if (!func(this[k1, j], this[k2, j]))
                                    {
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                    break;
                case 2:
                    {
                        for (int i = 0; i < W; i++)
                        {
                            for (int k1 = 0; k1 < H - 1; k1++)
                            {
                                for (int k2 = k1 + 1; k2 < H; k2++)
                                {
                                    if (!func(this[i, k1], this[i, k2]))
                                    {
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                    break;
            }

            return true;
        }
    }
}
